package com.wise.service.cms.content.upload;

import com.alibaba.fastjson.JSON;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.BlockEntry;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import com.wise.config.CloudBlockBlobCreator;
import com.wise.framework.basic.FileUtil;
import com.wise.framework.exception.Excep;
import com.wise.framework.session.GetAcceptLanguage;
import com.wise.summer.v1.cms.content.file.AddFile;
import com.wise.summer.v1.cms.content.uploadresource.AddUploadResource;
import com.wise.summer.v1.cms.content.uploadresource.DeleteUploadResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.summerframework.model.SummerService;
import org.summerframework.model.SummerServiceBean;

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.wise.model.content.ContentErrMsgs.Err_000100140010;
import static com.wise.model.content.ContentErrMsgs.Err_000100140019;


/**
 * 文件上传
 * updated by futao on 2019/04/15
 */
@Service
@SummerService
public class AddFileService implements SummerServiceBean<AddFile> {

    private static final Logger log = LoggerFactory.getLogger(AddFileService.class);

    private static final String MP4SUFFIX = ".mp4";

    private static final String AVISUFFIX = ".avi";

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    CloudBlockBlobCreator blockBlobCreator;

    @Override
    public void sum(AddFile model) {
        String lang = GetAcceptLanguage.s(true);
        //覆盖文件操作
        overwrite(model.getOverwrite(), model.getFilename());
        //上传文件不可重名
//        if (checkDuplicateName(model.getFilename())) {
//            throw Excep.le(Err_Upload.Err_000100140011);
//        }
        log.info("==========AddFile:{}", JSON.toJSONString(model));
        MultipartFile file = (MultipartFile) model.getFile();
        CloudBlockBlob blockBlob;
        try {
            log.info("########################getBlockBlobReference:{}", model.getIdentifier());
            blockBlob = blockBlobCreator.getBlockBlob(model.getFilename(), URLEncoder.encode(model.getFilename()));

            log.info("block 的唯一标示:{}     id={}   ", blockBlob.hashCode(), model.getIdentifier());
        } catch (URISyntaxException | StorageException e) {
            log.error(e.getMessage(), e);
            throw Excep.le(Err_000100140019);
        }
        //不存在，则进行保存
        try (InputStream input = file.getInputStream()) {
            //获取文件类型
            Integer fileType = model.getFileType();
            //对文件进行上传文件服务器
            String url = uploadBlock(model.getChunkNumber(), blockBlob, input, model.getChunkSize());
            log.info("########################uploadBlock，id:{}, number:{}, url:{}", model.getIdentifier(), model.getChunkNumber(), url);
        } catch (IOException e) {
            log.error("文件上传失败:{}", e.getMessage(), e);
            throw Excep.le(Err_000100140010);
        }

        //如果是最后一片,修改父文件的完成状态
        if (checkFileLast(model)) {
            //Azure需要批量提交
            ArrayList<BlockEntry> blockList = new ArrayList<>();
            for (Integer i = 1; i <= model.getTotalChunks(); i++) {
                String blockId = String.format("%05d", i);
                String blockIdEncoded = Base64.getEncoder().encodeToString(blockId.getBytes());
                log.info("blockId" + blockIdEncoded);
                blockList.add(new BlockEntry(blockIdEncoded));
            }
            try {
                blockBlob.commitBlockList(blockList);
                log.info("[File CommitBlockList Success, fileName={}] ", model.getFilename());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[File CommitBlockList Fail, fileName={}] ", model.getFilename());
            }
            String extName = FileUtil.getExtName(file.getOriginalFilename());
            AddUploadResource resourceModel = new AddUploadResource();
            resourceModel.setLang(lang);
            resourceModel.setOriginResourceName(file.getOriginalFilename());
            resourceModel.setResourceName(model.getFilename());
            resourceModel.setGroupId(model.getGroupId());
            resourceModel.setPath(blockBlob.getUri().toString());
            resourceModel.setResourcePath(blockBlob.getUri().toString());
            resourceModel.setFileSize(model.getTotalSize());
            resourceModel.setExtentionName(extName);
            resourceModel.setResourceType(model.getFileType());
            log.info("########################AddUploadResource json:{}", JSON.toJSONString(resourceModel));
            resourceModel.sum();
        }
        model.setSummerResult(true);
    }

    /**
     * 覆盖同名文件
     *
     * @param overwrite
     */
    private void overwrite(Integer overwrite, String fileName) {
        if (overwrite == null || overwrite == 0) {
            return;
        }
        //没有重复文件
        if (!checkDuplicateName(fileName)) {
            return;
        }
        //查询该文件id
        String sql = "select id from upload_resources where resource_name =" + "\"" + fileName + "\"";
        String id = jdbcTemplate.queryForObject(sql, String.class);
        //删除该文件
        DeleteUploadResource deleteUploadResource = new DeleteUploadResource();
        List<String> resourceIdList = new ArrayList<>();
        resourceIdList.add(id);
        deleteUploadResource.setList(resourceIdList);
        deleteUploadResource.sum();
        return;
    }

    /**
     * 上传文件不可重名
     */
    private boolean checkDuplicateName(String fileName) {
        //验证文件名
        String sql = "select count(*) from upload_resources where resource_name =" + "\"" + fileName + "\"";
        if (jdbcTemplate.queryForObject(sql, Integer.class) != 0) {
            return true;
        }
        return false;
    }

    /**
     * 分块列表
     *
     * @param blockNum        块数量
     * @param blockBlob       分块
     * @param fileInputStream 输入流
     * @param size            单块大小
     */
    private String uploadBlock(Integer blockNum, CloudBlockBlob blockBlob, InputStream fileInputStream, long size) {
        try {
            String blockId = String.format("%05d", blockNum);
            String blockIdEncoded = Base64.getEncoder().encodeToString(blockId.getBytes());
            blockBlob.uploadBlock(blockIdEncoded, fileInputStream, fileInputStream.available());
//            blockBlob.uploadProperties();
            log.info("blockIdEncoded" + blockIdEncoded);
            log.info("[File Block Upload Success, blockId={}, size={}, {}] ", blockId, size, blockBlob.getSnapshotID());
            return blockBlob.getUri().toString();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw Excep.le(Err_000100140019);
        }
    }


//    /**
//     * 增加对文件名后缀判断
//     */
//    private Boolean checkFile(String relativePath) {
//        if (relativePath.endsWith(MP4SUFFIX) || relativePath.endsWith(AVISUFFIX)) {
//            return true;
//        }
//        return false;
//    }


    /**
     * 功能描述:判断是否是最后一片
     *
     * @return:
     * @since: 1.0.0
     * @Author:
     * @Date:
     */
    private Boolean checkFileLast(AddFile model) {
        //保存当前快信息 保存7天
        redisTemplate.opsForValue().set(model.getIdentifier() + model.getChunkNumber(), "1", 60 * 60 * 24 * 7, TimeUnit.SECONDS);
        //判断所有块是否都上传玩了
        for (Integer i = 1; i <= model.getTotalChunks(); i++) {
            if (!redisTemplate.hasKey(model.getIdentifier() + i)) {
                return false;
            }
        }
        return true;
    }


}